package util

import (
	//"code.qschou.com/qschou/go_center_common/dlog"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"strings"
)

const (
	CHAR_SET               = "UTF-8"
	BASE_64_FORMAT         = "UrlSafeNoPadding"
	RSA_ALGORITHM_KEY_TYPE = "PKCS8"
	RSA_ALGORITHM_SIGN     = crypto.SHA256
)

func BuildYdyContent(req map[string]string) (str string, err error) {

	data := make(map[string]string)
	for k, v := range req {
		value := strings.TrimSpace(v)
		if len(value) <= 0 {
			continue
		}
		data[k] = value
	}
	str = MapSortByKey(data, "=", "&")
	//dlog.Info("unsign", str)
	return
}

// 数据加签
func XSign(privateKey, data string) (string, error) {
	h := RSA_ALGORITHM_SIGN.New()
	h.Write([]byte(data))
	hashed := h.Sum(nil)
	priKey, err := getPrivateKey(privateKey)
	if err != nil {
		return "", errors.New("private key error")
	}
	sign, err := rsa.SignPKCS1v15(rand.Reader, priKey, RSA_ALGORITHM_SIGN, hashed)
	if err != nil {
		return "", err
	}
	return base64.RawURLEncoding.EncodeToString(sign), err
}

// 数据验签
func XVerify(publicKey, data, sign string) error {
	h := RSA_ALGORITHM_SIGN.New()
	h.Write([]byte(data))
	hashed := h.Sum(nil)
	decodedSign, err := base64.RawURLEncoding.DecodeString(sign)
	if err != nil {
		return err
	}
	pubKey, err := getPublicKey(publicKey)
	if err != nil {
		return errors.New("public key error")
	}
	return rsa.VerifyPKCS1v15(pubKey, RSA_ALGORITHM_SIGN, hashed, decodedSign)
}

func getPrivateKey(privateKey string) (pri *rsa.PrivateKey, err error) {
	block, _ := pem.Decode([]byte(privateKey))
	if block == nil {
		return nil, errors.New("private key error")
	}
	priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	pri = priv.(*rsa.PrivateKey)
	return
}

func getPublicKey(publicKey string) (pub *rsa.PublicKey, err error) {
	block, _ := pem.Decode([]byte(publicKey))
	if block == nil {
		return nil, errors.New("public key error")
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	pub = pubInterface.(*rsa.PublicKey)
	return
}
